#include "DbRecord.h"
#include "Http/strCoding.h"
#include "Util/logger.h"
#include <cctype>
#include <string>

namespace mediakit {
DbRecord &DbRecord::Instance() {
    static DbRecord instance;
    return instance;
}

bool DbRecord::Init(const std::string &path) {
    try {
        if (!init) {
            _db = std::make_shared<sqlite3pp::database>(strCoding::GB2312ToUTF8(path).c_str());
            init = true;
        }
        return true;
    } catch (const std::exception &e) {
        ErrorL << e.what();
        return false;
    }
}

bool DbRecord::AddTable(const std::string &stream_id) {
    try {
        char buf[512];
        auto text = R"(CREATE TABLE IF NOT EXISTS "%s" (
                                                    "ID" INTEGER NOT NULL,
                                                    "Start" INTEGER,
                                                    "End" INTEGER,
                                                    "File" TEXT,
                                                    PRIMARY KEY ("ID")
                                                ))";

        snprintf(buf, sizeof(buf) - 1, text, stream_id.c_str());
        auto sql = strCoding::GB2312ToUTF8(buf);
        if (_db) {
            auto ret = _db->execute(sql.c_str());
            return ret == SQLITE_OK;
        }
    } catch (const std::exception &ex) {
        ErrorL << "Sqlite AddTable: " << ex.what();
    }
    return false;
}

bool DbRecord::AddRecord(const std::string &stream_id, uint64_t start, uint64_t end, const std::string &path) {
    try {
        char buf[512];
        auto text = R"(INSERT INTO "%s"("Start", "End", "File") VALUES (%lld, %lld, "%s"))";
        snprintf(buf, sizeof(buf) - 1, text, stream_id.c_str(), start, end, path.c_str());
        auto sql = strCoding::GB2312ToUTF8(buf);
        if (_db) {
            auto ret = _db->execute(sql.c_str());
            return ret == SQLITE_OK;
        }
    } catch (const std::exception &ex) {
        ErrorL << "Sqlite AddRecord: " << ex.what();
    }
    return true;
}

std::vector<std::shared_ptr<DbRecord::Mp4Item>>
DbRecord::Query(const std::string &stream_id, uint64_t start, uint64_t end) {
    std::vector<std::shared_ptr<DbRecord::Mp4Item>> files;
    try {
        char buf[512];
        auto text = R"(SELECT "Start","End","File" FROM "%s" WHERE "End" >= %lld AND Start <= %lld ORDER BY ID ASC)";
        //auto text = R"(SELECT "Start","End","File" FROM "%s" WHERE 1=1 ORDER BY ID ASC)";
        snprintf(buf, sizeof(buf) - 1, text, stream_id.c_str(), start, end);
        auto sql = strCoding::GB2312ToUTF8(buf);
        if (_db) {
            sqlite3pp::query query(*_db.get(), sql.c_str());
            for (auto iter = query.begin(); iter != query.end(); ++iter) {
                auto video = std::make_shared<DbRecord::Mp4Item>();
                video->file = strCoding::UTF8ToGB2312((*iter).get<const char *>(2));
                video->start = (*iter).get<int64_t>(0);
                video->end = (*iter).get<int64_t>(1);
                files.push_back(video);
            }
        }
    } catch (const std::exception &ex) {
        ErrorL << "Sqlite Query: " << ex.what();
    }
    return files;
}

bool DbRecord::Remove(const std::string &stream_id, const std::string &path) {
    try {
        char buf[512];
        auto text = R"(DELETE FROM "%s" WHERE File LIKE '%s')";
        snprintf(buf, sizeof(buf) - 1, text, stream_id.c_str(), path.c_str());
        auto sql = strCoding::GB2312ToUTF8(buf);
        if (_db) {
            auto ret = _db->execute(sql.c_str());
            return ret == SQLITE_OK;
        }
    } catch (const std::exception &ex) {
        ErrorL << "Sqlite Query: " << ex.what();
    }
    return false;
}

} // namespace mediakit
